home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / MacApp / MacApp 2.0 CD Release / MacApp 2.0 (Many Libraries) / Libraries / UMemory.inc1.p < prev    next >
Encoding:
Text File  |  1990-03-27  |  40.5 KB  |  1,687 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMemory.inc1.p }
  4. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  5.  
  6. {$IFC NOT qDebugTheDebugger}
  7. {$W+}
  8. {$R-}
  9. {$Init-}
  10. {$OV-}
  11. {$ENDC}
  12.  
  13. FUNCTION GrowZoneProc(needed: Size): LONGINT;
  14.     FORWARD;
  15.  
  16. PROCEDURE BuildCodeReserve(allocLim: Size;
  17.                            fromGZ: BOOLEAN);
  18.     FORWARD;
  19.  
  20. FUNCTION HandleIsEligible(h: Handle): BOOLEAN;
  21.     FORWARD;
  22.  
  23. {--------------------------------------------------------------------------------------------------}
  24.  
  25. PROCEDURE ALoadMacAppSeg;
  26.     EXTERNAL;
  27.  
  28. PROCEDURE APostLoadMacAppSeg;
  29.     EXTERNAL;
  30.  { LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
  31.   LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
  32.   procedure pointer, because no args are declared }
  33.  
  34. PROCEDURE EachFrameDo(calleeFrame, ppc: LONGINT;
  35.                       PROCEDURE DoToFrame(calleeFrame: LONGINT;
  36.                                           ppc: LONGINT;
  37.                                           callerFrame: LONGINT;
  38.                                           itsFrame: LONGINT));
  39.     EXTERNAL;
  40.  
  41. FUNCTION PreloadSegment(segNum: INTEGER): BOOLEAN;
  42.     EXTERNAL;
  43.  
  44. PROCEDURE CallNotify(h: Handle;
  45.                      routine: ProcPtr);
  46.     INLINE $205F, $4E90;                                { MOVE.L (A7)+,A0; JSR (A0) }
  47.  
  48. {--------------------------------------------------------------------------------------------------}
  49.  
  50.     {
  51.     These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
  52.     problem of multiple open resource maps in general); when running under the THINK™ environment,
  53.     CODE resources are not found in the same resource file as other application resources, so a
  54.     UseResFile call needs to be made to bring the project resource file into the search path.
  55.     "gCodeRefNum" is set up at initialization time.
  56.     !!! A much more general solution to "the resource problem" appears to be warranted.
  57.     }
  58.  
  59. {--------------------------------------------------------------------------------------------------}
  60. {$S MAMemoryRes}
  61.  
  62. FUNCTION MAGet1Resource(rType: ResType;
  63.                         rID: INTEGER): Handle;
  64.  
  65.     VAR
  66.         oldResFile:         INTEGER;
  67.  
  68.     BEGIN
  69.     oldResFile := MAUseResFile(gCodeRefNum);
  70.     MAGet1Resource := Get1Resource(rType, rID);
  71.     IF MAUseResFile(oldResFile) <> 0 THEN;
  72.     END;
  73.  
  74. {--------------------------------------------------------------------------------------------------}
  75. {$S MAMemoryRes}
  76.  
  77. FUNCTION MAGet1NamedResource(rType: ResType;
  78.                              name: Str255): Handle;
  79.  
  80.     VAR
  81.         oldResFile:         INTEGER;
  82.  
  83.     BEGIN
  84.     oldResFile := MAUseResFile(gCodeRefNum);
  85.     MAGet1NamedResource := Get1NamedResource(rType, name);
  86.     IF MAUseResFile(oldResFile) <> 0 THEN;
  87.     END;
  88.  
  89. {--------------------------------------------------------------------------------------------------}
  90. {$S MAMemoryRes}
  91.  
  92. FUNCTION MAGet1IndResource(rType: ResType;
  93.                            index: INTEGER): Handle;
  94.  
  95.     VAR
  96.         oldResFile:         INTEGER;
  97.  
  98.     BEGIN
  99.     oldResFile := MAUseResFile(gCodeRefNum);
  100.     MAGet1IndResource := Get1IndResource(rType, index);
  101.     IF MAUseResFile(oldResFile) <> 0 THEN;
  102.     END;
  103.  
  104. {--------------------------------------------------------------------------------------------------}
  105. {$S MAMemoryRes}
  106.  
  107. FUNCTION MACount1Resources(rType: ResType): INTEGER;
  108.  
  109.     VAR
  110.         oldResFile:         INTEGER;
  111.  
  112.     BEGIN
  113.     oldResFile := MAUseResFile(gCodeRefNum);
  114.     MACount1Resources := Count1Resources(rType);
  115.     IF MAUseResFile(oldResFile) <> 0 THEN;
  116.     END;
  117.  
  118. {--------------------------------------------------------------------------------------------------}
  119. {$S MAMemoryRes}
  120.  
  121. FUNCTION MAGetResource(rType: ResType;
  122.                        rID: INTEGER): Handle;
  123.  
  124.     VAR
  125.         h:                    Handle;
  126.         oldResFile:         INTEGER;
  127.  
  128.     BEGIN
  129.     oldResFile := MAUseResFile(gCodeRefNum);
  130.     h := GetResource(rType, rID);
  131.     IF MAUseResFile(oldResFile) <> 0 THEN;
  132.  
  133.     IF HomeResFile(h) <> gCodeRefNum THEN
  134.         h := NIL;
  135.  
  136.     MAGetResource := h;
  137.     END;
  138.  
  139. {--------------------------------------------------------------------------------------------------}
  140. {$S MAMemoryRes}
  141.  
  142. FUNCTION MAGetNamedResource(rType: ResType;
  143.                             name: Str255): Handle;
  144.  
  145.     VAR
  146.         h:                    Handle;
  147.         oldResFile:         INTEGER;
  148.  
  149.     BEGIN
  150.     oldResFile := MAUseResFile(gCodeRefNum);
  151.     h := GetNamedResource(rType, name);
  152.     IF MAUseResFile(oldResFile) <> 0 THEN;
  153.  
  154.     IF HomeResFile(h) <> gCodeRefNum THEN
  155.         h := NIL;
  156.  
  157.     MAGetNamedResource := h;
  158.     END;
  159.  
  160. {--------------------------------------------------------------------------------------------------}
  161. {$S MAMemoryRes}
  162.  
  163. FUNCTION MAGetIndResource(rType: ResType;
  164.                           index: INTEGER): Handle;
  165.  
  166.     VAR
  167.         h:                    Handle;
  168.         oldResFile:         INTEGER;
  169.  
  170.     BEGIN
  171.     oldResFile := MAUseResFile(gCodeRefNum);
  172.     h := GetIndResource(rType, index);
  173.     IF MAUseResFile(oldResFile) <> 0 THEN;
  174.  
  175.     IF HomeResFile(h) <> gCodeRefNum THEN
  176.         h := NIL;
  177.  
  178.     MAGetIndResource := h;
  179.     END;
  180.  
  181. {--------------------------------------------------------------------------------------------------}
  182. {$S MAMemoryRes}
  183.  
  184. FUNCTION MACountResources(rType: ResType): INTEGER;
  185.  
  186.     VAR
  187.         oldResFile:         INTEGER;
  188.  
  189.     BEGIN
  190.     oldResFile := MAUseResFile(gCodeRefNum);
  191.     MACountResources := CountResources(rType);
  192.     IF MAUseResFile(oldResFile) <> 0 THEN;
  193.     END;
  194.  
  195. {--------------------------------------------------------------------------------------------------}
  196. {$S MAMemoryRes}
  197.  
  198. FUNCTION GetSegResource(segNum: INTEGER): Handle;
  199.  
  200.     BEGIN
  201.     IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  202.         GetSegResource := MAGet1Resource(kCode, segNum)
  203.     ELSE
  204.         GetSegResource := MAGetResource(kCode, segNum);
  205.     END;
  206.  
  207. {--------------------------------------------------------------------------------------------------}
  208. {$S MAMiniInit}
  209.  
  210. PROCEDURE AddAllRsrc(rType: ResType;
  211.                      toList: HandleListHandle);
  212.  
  213.     VAR
  214.         oldResLoad:         BOOLEAN;
  215.         i:                    INTEGER;
  216.         h:                    Handle;
  217.         theID:                INTEGER;
  218.         theType:            ResType;
  219.         theName:            Str255;
  220.  
  221.     BEGIN
  222.     oldResLoad := GetResLoad;
  223.     SetResLoad(FALSE);
  224.  
  225.     FOR i := 1 TO CountResources(rType) DO
  226.         BEGIN
  227.         h := GetIndResource(rType, i);
  228.         GetResInfo(h, theID, theType, theName);
  229.  
  230.   { If there is a ROM resource for this type and ID, don't put it
  231.    on the list. }
  232.         UseROMMap(FALSE);
  233.         h := GetResource(rType, theID);
  234.         UseROMMap(FALSE);
  235.         IF HomeResFile(h) <> 1 THEN
  236.             AddHandle(h, toList);
  237.  
  238.         END;
  239.  
  240.     SetResLoad(oldResLoad);
  241.     END;
  242.  
  243. {--------------------------------------------------------------------------------------------------}
  244. {$S MAMiniInit}
  245.  
  246. PROCEDURE AddHandle(h: Handle;
  247.                     toList: HandleListHandle);
  248.  
  249.     VAR
  250.         offset:             LONGINT;
  251.  
  252.     BEGIN
  253.     offset := Munger(Handle(toList), 0, NIL, 0, @h, 4);
  254.     FailMemError;
  255.     END;
  256.  
  257. {--------------------------------------------------------------------------------------------------}
  258. {$S MAMiniInit}
  259.  
  260. FUNCTION AddSegSizes(segRsrc: Handle): LONGINT;
  261.  
  262.     VAR
  263.         p:                    SignedBytePtr;
  264.         oldResLoad:         BOOLEAN;
  265.         total:                LONGINT;
  266.         seg:                Handle;
  267.         i:                    INTEGER;
  268.         s:                    Str255;
  269.  
  270.     BEGIN
  271.     LockHandleHigh(segRsrc);
  272.  
  273.     oldResLoad := GetResLoad;
  274.     SetResLoad(FALSE);
  275.  
  276.     p := SignedBytePtr(segRsrc^);
  277.     i := IntegerPtr(p)^;
  278.     p := SignedBytePtr(Ord(p) + 2);
  279.  
  280.     total := 0;
  281.  
  282.     WHILE i > 0 DO
  283.         BEGIN
  284.         BlockMove(Ptr(p), @s, p^ + 1);
  285.  
  286.         p := SignedBytePtr(Ord(p) + p^ + 1);
  287.         i := i - 1;
  288.  
  289.         IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  290.             seg := MAGet1NamedResource(kCode, s)
  291.         ELSE
  292.             seg := MAGetNamedResource(kCode, s);
  293.  
  294.         IF seg <> NIL THEN
  295.             total := total + SizeResource(seg) + 8;
  296.         END;
  297.  
  298.     AddSegSizes := total;
  299.  
  300.     SetResLoad(oldResLoad);
  301.  
  302.     HUnlock(segRsrc);
  303.     END;
  304.  
  305. {--------------------------------------------------------------------------------------------------}
  306. {$S MAMemoryRes}
  307. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  308.  
  309. PROCEDURE BuildAllReserves;
  310.  
  311.     CONST
  312.         initVal             = $F7;
  313.  
  314.     VAR
  315.         oldPerm:            BOOLEAN;
  316.         {$IFC qDebug}
  317.         theSize:            Size;
  318.         {$EndC}
  319.  
  320.     BEGIN
  321.   { set the permanent flag to ensure that the code reserve is
  322.    actually allocated and not given up to the low space reserve }
  323.     oldPerm := pPermAllocation;
  324.     pPermAllocation := TRUE;
  325.  
  326.     { make sure code reserve is OK }
  327.     BuildCodeReserve(kGZMaxAlloc, FALSE);
  328.  
  329.     { reallocate the low space handle, if necessary }
  330.     IF IsHandlePurged(pMemReserve) THEN
  331.         BEGIN
  332.  
  333.         ReallocHandle(pMemReserve, pSzMemReserve);
  334.         {$IFC qDebug}
  335.         theSize := GetHandleSize(pMemReserve);
  336.         {$Push} {$R-}
  337.         IF theSize <> 0 THEN
  338.             BlockSet(pMemReserve^, theSize, initVal);
  339.         {$Pop}
  340.         {$EndC}
  341.         END;
  342.  
  343.     { reset the permanent flag }
  344.     pPermAllocation := oldPerm;
  345.     END;
  346. {$Pop}
  347.  
  348. {--------------------------------------------------------------------------------------------------}
  349. {$S MAMemoryRes}
  350. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  351.  
  352. PROCEDURE BuildCodeReserve(allocLim: Size;
  353.                            fromGZ: BOOLEAN);
  354.  
  355.     CONST
  356.         initVal             = $F7;
  357.  
  358.     VAR
  359.         needed:             Size;
  360.         avail:                Size;
  361.         canPurge:            Handle;
  362.         {$IFC qDebug}
  363.         theSize:            Size;
  364.         {$EndC}
  365.  
  366.     BEGIN
  367.     pOKCodeReserve := TRUE;                             { default value }
  368.  
  369.     {$IFC qDebug}
  370.     pReserveShortfall := 0;
  371.  
  372.     IF NOT pPermAllocation THEN
  373.         ProgramBreak('BuildCodeReserve called with pPermAllocation = FALSE');
  374.     {$ENDC qDebug}
  375.  
  376.     IF NOT pReserveExists THEN
  377.         BEGIN
  378.         pReserveExists := TRUE;                         { default value }
  379.  
  380.         { free the current code reserve }
  381.         IF HandleIsEligible(pCodeReserve) THEN
  382.             EmptyHandle(pCodeReserve);
  383.  
  384.         { compute amt actually needed }
  385.         needed := Min(pSzCodeReserve - TotalTempSize(FALSE, canPurge) - 8, allocLim);
  386.  
  387.         IF needed > 0 THEN
  388.             BEGIN
  389.             { make as much memory available as possible }
  390.             IF HandleIsEligible(pMemReserve) THEN
  391.                 EmptyHandle(pMemReserve);
  392.  
  393.             IF fromGZ THEN                                { Never purge or compact from GrowZone }
  394.                 avail := allocLim
  395.             ELSE
  396.                 BEGIN
  397.                 PurgeMem(needed);
  398.                 avail := CompactMem(needed);
  399.                 END;
  400.  
  401.             IF avail < needed THEN                        { could not get the whole reserve }
  402.                 BEGIN
  403.                 {$IFC qDebug}
  404.                 pReserveShortfall := needed - avail;
  405.                 {$ENDC}
  406.  
  407.                 pOKCodeReserve := FALSE;
  408.                 pReserveExists := FALSE;
  409.  
  410.                 needed := avail;                        { get the most we can }
  411.                 END;
  412.  
  413.             IF IsHandlePurged(pCodeReserve) | HandleIsEligible(pCodeReserve) THEN
  414.                 ReallocHandle(pCodeReserve, needed);
  415.             {$IFC qDebug}
  416.             theSize := GetHandleSize(pCodeReserve);
  417.             {$Push} {$R-}
  418.             IF theSize <> 0 THEN
  419.                 BlockSet(pCodeReserve^, theSize, initVal);
  420.             {$Pop}
  421.             {$EndC}
  422.             IF NOT IsHandlePurged(pCodeReserve) THEN
  423.                 BEGIN
  424.                 { Large handles are almost as bad as nonrelocatable blocks.
  425.                     Try to get this guy out of the way, just in case.}
  426.                 IF NOT fromGZ THEN
  427.                     MoveHHi(pCodeReserve);
  428.                 END;
  429.             END;
  430.         END;
  431.     END;
  432. {$Pop}
  433.  
  434. {--------------------------------------------------------------------------------------------------}
  435. {$S MAMemoryRes}
  436.  
  437. FUNCTION CheckReserve: BOOLEAN;
  438.  
  439.     BEGIN
  440.     BuildAllReserves;
  441.     CheckReserve := pOKCodeReserve;
  442.     END;
  443.  
  444. {--------------------------------------------------------------------------------------------------}
  445. {$IFC qDebug}
  446. {$S MAMemoryRes}
  447.  
  448. PROCEDURE CheckRsrcUsage;
  449.  
  450.     VAR
  451.         sz:                 LONGINT;
  452.         h:                    Handle;
  453.         s:                    Str255;
  454.  
  455.     BEGIN
  456.     sz := TotalTempSize(TRUE, h);
  457.     IF sz > gMaxLockedRsrc THEN
  458.         BEGIN
  459.         gMaxLockedRsrc := sz;
  460.         IF gRsrcReport THEN
  461.             BEGIN
  462.             NumToString(gMaxLockedRsrc, s);
  463.             s := Concat('  == New maximum resources usage: ', s, ' ==');
  464.             ProgramReport(s, gMemMgtBreak);
  465.             END;
  466.         END;
  467.     END;
  468. {$ENDC qDebug}
  469.  
  470. {--------------------------------------------------------------------------------------------------}
  471. {$IFC qDebug}
  472. {$S MADebug}
  473.  
  474. PROCEDURE DoChangeReserve(alter: BOOLEAN;
  475.                           VAR codeReserve, codeShort, lowSpaceReserve: LONGINT;
  476.                           VAR gotCode, gotLowSpace: BOOLEAN);
  477.  
  478.     VAR
  479.         x:                    LONGINT;
  480.         s:                    Str255;
  481.  
  482.     BEGIN
  483.     IF alter THEN
  484.         BEGIN
  485.         Write('code reserve size = ', pSzCodeReserve: 1, '  ');
  486.         IF pOKCodeReserve THEN
  487.             Writeln(' (OK)')
  488.         ELSE
  489.             Writeln(' (gone)');
  490.  
  491.         Write('low space reserve size = ', pSzMemReserve: 1, '  ');
  492.         IF NOT IsHandlePurged(pMemReserve) THEN
  493.             Writeln(' (OK)')
  494.         ELSE
  495.             Writeln(' (gone)');
  496.  
  497.         Writeln;
  498.  
  499.         Write('New code reserve (-1 = no change): ');
  500.         Readln(x);
  501.         IF x >= 0 THEN
  502.             codeReserve := x
  503.         ELSE
  504.             codeReserve := pSzCodeReserve;
  505.  
  506.         Write('New low space reserve (-1 = no change): ');
  507.         Readln(x);
  508.         IF x >= 0 THEN
  509.             lowSpaceReserve := x
  510.         ELSE
  511.             lowSpaceReserve := pSzMemReserve;
  512.  
  513.         Write('Reset max resource usage (Y or N) [N]? ');
  514.         Readln(s);
  515.         IF s <> '' THEN
  516.             IF (s[1] = 'y') | (s[1] = 'Y') THEN
  517.                 BEGIN
  518.                 gMaxLockedRsrc := 0;
  519.                 END;
  520.  
  521.         Writeln;
  522.  
  523.         SetReserveSize(codeReserve, lowSpaceReserve);
  524.         END
  525.     ELSE
  526.         BuildAllReserves;
  527.  
  528.     codeReserve := pSzCodeReserve;
  529.     codeShort := pReserveShortfall;
  530.     lowSpaceReserve := pSzMemReserve;
  531.     gotCode := pOKCodeReserve;
  532.     gotLowSpace := NOT IsHandlePurged(pMemReserve);
  533.     END;
  534. {$ENDC qDebug}
  535.  
  536. {--------------------------------------------------------------------------------------------------}
  537. {$S MAMiniInit}
  538.  
  539. PROCEDURE DoInitUMemory(VAR sizeTempReserve, sizeLowSpaceReserve: Size);
  540.  
  541.  { Called from InitUMemory so that InitUMemory can be in the main segment
  542.   and this code can be in another (unloadable) segment. }
  543.  
  544.     TYPE
  545.         Mem                 = RECORD                    { format of the mem! resource }
  546.             codeVal, lowSpaceVal, stackVal: LONGINT;
  547.             END;
  548.         MemPtr                = ^Mem;
  549.         MemHandle            = ^MemPtr;
  550.  
  551.     VAR
  552.         i:                    INTEGER;
  553.         oldResLoad:         BOOLEAN;
  554.         seg:                Handle;
  555.         StackTot:            LONGINT;
  556.         h:                    Handle;
  557.         rsrcID:             INTEGER;
  558.         rsrcType:            ResType;
  559.         rsrcName:            Str255;
  560.         lastRsrc:            INTEGER;
  561.         mainSegment, utilitySegment: INTEGER;
  562.  
  563.     BEGIN
  564.     { Initialize memory management globals }
  565.     pPermAllocation := FALSE;
  566.     pMemReserve := NewHandle(0);
  567.     FailNil(pMemReserve);
  568.  
  569.     pSzMemReserve := 0;
  570.     pCodeReserve := NewHandle(0);
  571.     FailNil(pCodeReserve);
  572.  
  573.     pSzCodeReserve := 0;
  574.     gGZPurgeNotify := NIL;
  575.     pOKCodeReserve := TRUE;
  576.     pReserveExists := FALSE;
  577.     {$IFC qDebug}
  578.     gSegReport := FALSE;
  579.     {$EndC}
  580.  
  581.     gUnloadAllSegs := TRUE;
  582.  
  583.     gCodeRefNum := HomeResFile(GetResource(kCode, 1));    { Get homeresfile of "Main".
  584.                                                         It better be there!!}
  585.     pMaxSegNum := 0;
  586.  
  587.     {###########################################}
  588.     { No resource loading }
  589.  
  590.     oldResLoad := GetResLoad;
  591.     SetResLoad(FALSE);
  592.  
  593.     { Figure the highest segment number }
  594.     IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  595.         lastRsrc := MACount1Resources(kCode) - 1
  596.     ELSE
  597.         lastRsrc := MACountResources(kCode) - 1;
  598.  
  599.     { some development systems may not have contiguous numbering of CODE segments.
  600.     try to be polite about handling it }
  601.     FOR i := 1 TO lastRsrc DO
  602.         BEGIN
  603.         IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  604.             seg := MAGet1IndResource(kCode, i)
  605.         ELSE
  606.             seg := MAGetIndResource(kCode, i);
  607.         { we only have an index… find the real resource ID and keep track
  608.         of the highest one }
  609.         IF (seg <> NIL) THEN
  610.             BEGIN
  611.             GetResInfo(seg, rsrcID, rsrcType, rsrcName);
  612.             pMaxSegNum := Max(rsrcID, pMaxSegNum);
  613.             END;
  614.         END;
  615.  
  616.  
  617.     SetResLoad(oldResLoad); { in case of failure }
  618.  
  619.     { Allocate the master segment lists.}
  620.     gCodeSegs := HandleListHandle(NewHandle(pMaxSegNum * SizeOf(Handle)));
  621.     FailNil(gCodeSegs);
  622.  
  623.     gIsResidentSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  624.     FailNil(gIsResidentSeg);
  625.  
  626.     gIsLoadedSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  627.     FailNil(gIsLoadedSeg);
  628.  
  629.     { (NOTE: assumes application doesn't change the CODE segment size at runtime
  630.     (a very safe assumption)). Used in GetSegFromPC. }
  631.     pSegSize := LongListHandle(NewHandle(SizeOf(LONGINT) * pMaxSegNum));
  632.     FailNil(pSegSize);
  633.  
  634.     oldResLoad := GetResLoad; { OK, suppress segment loading again }
  635.     SetResLoad(FALSE);    { !!! Need an MAResLoad that returns old state }
  636.  
  637.     { Initialize segment lists.}
  638.     FOR i := 1 TO pMaxSegNum DO
  639.         gIsResidentSeg^^[i] := FALSE;
  640.  
  641.     { Segments and their sizes and actual loaded state (helps catch preloads) }
  642.     FOR i := 1 TO pMaxSegNum DO
  643.         BEGIN
  644.         seg := GetSegResource(i);
  645.         gCodeSegs^^[i] := seg;
  646.         if seg <> NIL THEN { seg is non-nil if the segment number exists }
  647.             BEGIN
  648.             pSegSize^^[i] := SizeResource(seg);
  649.             gIsLoadedSeg^^[i] := IsHandleLocked(seg);            
  650.             END
  651.         ELSE
  652.             BEGIN
  653.             pSegSize^^[i] := 0;
  654.             gIsLoadedSeg^^[i] := FALSE;            
  655.             END;
  656.         END;
  657.  
  658.     SetResLoad(oldResLoad);
  659.     {###########################################}
  660.  
  661.     mainSegment := GetSegNumber(@InitUMemory);            { Main is always resident }
  662.     gIsResidentSeg^^[mainSegment] := TRUE;
  663.     gIsLoadedSeg^^[mainSegment] := TRUE;
  664.  
  665.     utilitySegment := GetSegNumber(@UnloadAllSegments); { Utilities are always resident }
  666.     gIsResidentSeg^^[utilitySegment] := TRUE;
  667.     gIsLoadedSeg^^[utilitySegment] := TRUE;
  668.  
  669.     { init the gSysMemList }
  670.     gSysMemList := HandleListHandle(NewHandle(0));
  671.     FailNil(gSysMemList);
  672.  
  673.     AddAllRsrc('LDEF', gSysMemList);
  674.     AddAllRsrc('CDEF', gSysMemList);
  675.     AddAllRsrc('MDEF', gSysMemList);
  676.     AddAllRsrc('WDEF', gSysMemList);
  677.     AddAllRsrc('PACK', gSysMemList);
  678.  
  679.     { Compute memory slop needed }
  680.     sizeTempReserve := 0;
  681.     sizeLowSpaceReserve := 0;
  682.     StackTot := 0;
  683.  
  684.     FOR i := 1 TO CountResources('seg!') DO
  685.         BEGIN
  686.         h := GetIndResource('seg!', i);
  687.         sizeTempReserve := sizeTempReserve + AddSegSizes(h);
  688.         ReleaseResource(h);
  689.         END;
  690.  
  691.     FOR i := 1 TO CountResources('mem!') DO
  692.         BEGIN
  693.         h := GetIndResource('mem!', i);
  694.         WITH MemHandle(h)^^ DO
  695.             BEGIN
  696.             sizeTempReserve := sizeTempReserve + codeVal;
  697.             sizeLowSpaceReserve := sizeLowSpaceReserve + lowSpaceVal;
  698.             StackTot := StackTot + stackVal;
  699.             END;
  700.         ReleaseResource(h);
  701.         END;
  702.  
  703.     SetStackSpace(StackTot);
  704.  
  705.     MaxApplZone;
  706.  
  707.     gApp1MemList := NIL;
  708.     gApp2MemList := NIL;
  709.  
  710.     END;
  711.  
  712. {--------------------------------------------------------------------------------------------------}
  713. {$S MAMemoryRes}
  714.  
  715. PROCEDURE FailNoReserve;
  716.  
  717.     BEGIN
  718.     IF NOT CheckReserve THEN
  719.         Failure(memFullErr, 0);
  720.     END;
  721.  
  722. {--------------------------------------------------------------------------------------------------}
  723. {$S MAMemoryRes}
  724.  
  725. PROCEDURE FailSpaceIsLow;
  726.  
  727. {$IFC qDebug}
  728.  
  729.     VAR
  730.         s:                    MAName;
  731.         {$ENDC}
  732.  
  733.     BEGIN
  734.     {$IFC qDebug}
  735.     IF gAskFailure & CanReadLn THEN
  736.         BEGIN
  737.         GetCallersMethodName(s);
  738.         IF ReadYesNo(Concat('FailSpaceIsLow called by ', s, '.  Return true(Y or N) [N]? ')) THEN
  739.             Failure(memFullErr, 0);
  740.         END;
  741.     {$ENDC}
  742.  
  743.     IF MemSpaceIsLow THEN
  744.         Failure(memFullErr, 0);
  745.     END;
  746.  
  747. {--------------------------------------------------------------------------------------------------}
  748. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  749. {$S MAMemoryRes}
  750.  
  751. PROCEDURE GetReserveSize(VAR szCodeReserve, szMemReserve: Size);
  752.  
  753.     BEGIN
  754.     szCodeReserve := pSzCodeReserve;
  755.     szMemReserve := pSzMemReserve;
  756.     END;
  757. {$Pop}
  758.  
  759. {--------------------------------------------------------------------------------------------------}
  760. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  761.                                                          cannot call to any other segment from this
  762.                                                          procedure }
  763. {$S MAMemoryRes}                                        { Shouldn't be unloaded }
  764.  
  765. FUNCTION GetSegFromPC(ppc: LONGINT): INTEGER;
  766.  
  767.     VAR
  768.         pc:                 LONGINT;
  769.         i:                    INTEGER;
  770.         seg:                Handle;
  771.         segStart:            LONGINT;
  772.  
  773.     BEGIN
  774.     pc := LongintPtr(ppc)^;
  775.  
  776.     GetSegFromPC := 0;                                    { default return }
  777.  
  778.     { Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs = NIL
  779.     before using it. }
  780.     IF (gCodeSegs <> NIL) THEN
  781.         FOR i := 1 TO pMaxSegNum DO
  782.             BEGIN
  783.             seg := gCodeSegs^^[i];                        { get segment handle }
  784.             IF (seg <> NIL) & NOT IsHandlePurged(seg) THEN { it's in memory }
  785.                 BEGIN
  786.                 segStart := StripLong(seg^);            { get segment start }
  787.                 IF (pc >= segStart) & (pc < segStart + pSegSize^^[i]) THEN
  788.                     BEGIN
  789.                     GetSegFromPC := i;
  790.                     LEAVE;
  791.                     END;
  792.                 END;
  793.             END;
  794.     END;
  795. {$Pop}
  796.  
  797. {--------------------------------------------------------------------------------------------------}
  798. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  799.                                                          cannot call to any other segment from this
  800.                                                          procedure }
  801. {$S MAMemoryRes}                                        { must be in Main segment because we call
  802.                                                          this in order to make the resident segment
  803.                                                          resident }
  804.  
  805. FUNCTION GetSegNumber(aProc: ProcPtr): INTEGER;
  806. { Gets seg number from a Jump table address }
  807.  
  808.     CONST
  809.         kLoaded             = $4EF9;                    { if loaded then a JMP instruction }
  810.         kUnLoaded            = $3F3C;                    { if unloaded then a LoadSeg trap }
  811.  
  812.     VAR
  813.         i:                    INTEGER;
  814.         jt:                 LONGINT;
  815.         segNum:             INTEGER;
  816.         seg:                Handle;
  817.         segStart:            LONGINT;
  818.  
  819.     BEGIN
  820.     IF IntegerPtr(aProc)^ = kLoaded THEN                { loaded segment }
  821.         GetSegNumber := IntegerPtr(Ord(aProc) - 2)^
  822.     ELSE IF IntegerPtr(aProc)^ = kUnLoaded THEN         { unloaded segment }
  823.         GetSegNumber := IntegerPtr(Ord(aProc) + 2)^
  824.     ELSE                                                { routine that computed @proc was in same
  825.                                                          segment as the proc }
  826.         BEGIN
  827.         {$IFC qDebug}
  828.         ProgramBreak('GetSegNumber was not passed an jump table address');
  829.         {$ENDC}
  830.         GetSegNumber := 0;
  831.         END;
  832.     END;
  833. {$Pop}
  834.  
  835. {--------------------------------------------------------------------------------------------------}
  836. {$S MAMemoryRes}
  837. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  838.  
  839. FUNCTION GetSegSize(segNum: INTEGER): Size;
  840.  
  841.     VAR
  842.         curResLoad:         BOOLEAN;
  843.         seg:                Handle;
  844.  
  845.     BEGIN
  846.     GetSegSize := pSegSize^^[segNum];
  847.     END;
  848. {$Pop}
  849.  
  850. {--------------------------------------------------------------------------------------------------}
  851. {$S MAMemoryRes}
  852. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  853.  
  854. FUNCTION GrowZoneProc(needed: Size): LONGINT;
  855.  
  856.     VAR
  857.         result:             LONGINT;
  858.         canPurge:            Handle;
  859.         codeSize:            Size;
  860.         reserveSize:        LONGINT;
  861.         OldA5:                LONGINT;
  862.  
  863.     BEGIN
  864.     OldA5 := SetCurrentA5;                                { Can be called from other worlds }
  865.  
  866.     result := 0;                                        { default is to fail }
  867.  
  868.     { on a temp alloc, free all code slack immediately }
  869.     IF NOT pPermAllocation & HandleIsEligible(pCodeReserve) THEN
  870.         BEGIN
  871.         EmptyHandle(pCodeReserve);
  872.         pReserveExists := FALSE;
  873.         result := 1;
  874.         END;
  875.  
  876.     IF result = 0 THEN                                    { try harder: see if we can purge a code
  877.                                                          segment or reduce the code reserve handle
  878.                                                          }
  879.         BEGIN
  880.         { compute size of resources currently in memory }
  881.  
  882.         codeSize := TotalTempSize(FALSE, canPurge);
  883.  
  884.         { see if the code reserve handle is too large }
  885.  
  886.         IF HandleIsEligible(pCodeReserve) THEN
  887.             { we have a code reserve handle; this implies permanent allocation,
  888.             otherwise the handle would have been emptied above }
  889.             BEGIN
  890.             reserveSize := GetHandleSize(pCodeReserve);
  891.  
  892.             { the following test is an optimization to avoid calling
  893.             BuildCodeReserve if there is no hope of reducing
  894.             the code reserve handle }
  895.             IF codeSize + reserveSize + 8 > pSzCodeReserve THEN
  896.                 BEGIN                                    { reserve is too big }
  897.                 pReserveExists := FALSE;
  898.                 { this should lower the code reserve }
  899.                 BuildCodeReserve(reserveSize, TRUE);
  900.  
  901.                 { see if we succeeded in freeing some memory }
  902.                 IF IsHandlePurged(pCodeReserve) THEN
  903.                     result := 1
  904.                 ELSE IF GetHandleSize(pCodeReserve) < reserveSize THEN
  905.                     result := 1;
  906.                 END;
  907.             END;
  908.  
  909.         IF (result = 0) & (canPurge <> NIL) & (NOT pPermAllocation |
  910.            IsHandlePurged(pCodeReserve)) THEN           { got something; only purge it if this is
  911.                                                          temporary OR we know there is too much
  912.                                                          code in memory already }
  913.             BEGIN
  914.             IF gGZPurgeNotify <> NIL THEN
  915.                 CallNotify(canPurge, gGZPurgeNotify);
  916.  
  917.             reserveSize := GetHandleSize(canPurge);
  918.             HPurge(canPurge);
  919.             EmptyHandle(canPurge);
  920.             pReserveExists := FALSE;
  921.  
  922.             IF pPermAllocation THEN                     { don't free too much however }
  923.                 BuildCodeReserve(reserveSize, TRUE);
  924.  
  925.             result := 1;
  926.             END;
  927.         END;
  928.  
  929.     IF (result = 0) & HandleIsEligible(pMemReserve) THEN { last ditch attempt-free emergency
  930.                                                           reserve}
  931.         BEGIN
  932.         EmptyHandle(pMemReserve);
  933.         result := 1;
  934.         END;
  935.  
  936.     GrowZoneProc := result;
  937.  
  938.     OldA5 := SetA5(OldA5);
  939.     END;
  940. {$Pop}
  941.  
  942. {--------------------------------------------------------------------------------------------------}
  943. {$S MAMemoryRes}
  944. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  945.  
  946. FUNCTION HandleIsEligible(h: Handle): BOOLEAN;
  947.  
  948.     BEGIN
  949.     IF IsHandlePurged(h) THEN
  950.         HandleIsEligible := FALSE
  951.     ELSE
  952.         HandleIsEligible := (h <> GetGZMoveHnd) & (h <> GetGZRootHnd);
  953.     END;
  954. {$Pop}
  955.  
  956. {--------------------------------------------------------------------------------------------------}
  957. {$S MAMemoryRes}                                        { Must be in same segment as grow zone proc
  958.                                                          }
  959. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  960.  
  961. PROCEDURE InstallGrowZoneProc;
  962. { Once called the grow zone proc's segment CANNOT be moved since we're passing a NON-JT address
  963. to SetGrowZone (so we can be called from "other worlds" }
  964.  
  965.     VAR
  966.         aZone:                THz;
  967.  
  968.     BEGIN
  969.     aZone := ApplicZone;
  970.     aZone^.flags := BOR(aZone^.flags, $0400);
  971.   { set the Memory Manager bit that says to always call the
  972.    Grow Zone proc, even in "non-critical" situations }
  973.  
  974.     SetGrowZone(@GrowZoneProc);
  975.  
  976.     END;
  977. {$Pop}
  978.  
  979. {--------------------------------------------------------------------------------------------------}
  980. {$S Main}                                                { Must be in main segment and called from
  981.                                                          main segment }
  982.  
  983. PROCEDURE InitUMemory;
  984.  
  985.     VAR
  986.         codeRes, lowSpaceRes: Size;
  987.         miniInitSeg, utilitySeg: Handle;
  988.         mainSeg:    integer;
  989.  
  990.     BEGIN
  991.  
  992.     { Get these segments out of the way so that when DoInitUMemory gets called and the next
  993.     block of master pointers gets allocated they won't constipate the heap }
  994.     miniInitSeg := GetResource(kCode, GetSegNumber(@DoInitUMemory));
  995.     IF miniInitSeg <> NIL THEN
  996.         BEGIN
  997.         UnLoadSeg(@DoInitUMemory);
  998.         LockHandleHigh(miniInitSeg);
  999.         END;
  1000.  
  1001.     DoInitUMemory(codeRes, lowSpaceRes);
  1002.  
  1003.     UnloadAllSegments;                                    { get init segment(s) out of middle of heap,
  1004.                                                          so SetReserveSize has maximum space to
  1005.                                                          work with }
  1006.  
  1007.     IF miniInitSeg <> NIL THEN                            { Yes, this would eventually get purged if
  1008.                                                          the space was needed badly enough, but
  1009.                                                          that happens very late in the game and can
  1010.                                                          confound the unwary }
  1011.         EmptyHandle(miniInitSeg);
  1012.  
  1013.     InstallGrowZoneProc;
  1014.  
  1015.     SetReserveSize(codeRes, lowSpaceRes);
  1016.     IF NOT pOKCodeReserve THEN                            { couldn't get code reserve. Can't continue
  1017.                                                          }
  1018.         Failure(memFullErr, 0)
  1019.     ELSE
  1020.     { Set up the LoadSeg patch }
  1021.  
  1022.         FailOSErr(PatchTrap(pSegLoadPatch, _LoadSeg, @ALoadMacAppSeg));
  1023.  
  1024.     END;
  1025.  
  1026. {--------------------------------------------------------------------------------------------------}
  1027. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1028.                                                          cannot call to any other segment from this
  1029.                                                          procedure }
  1030. {$S MAMemoryRes}                                        { must be in Main segment }
  1031.  
  1032. FUNCTION LoadMacAppSegment(segNum: INTEGER): LONGINT;
  1033.  
  1034.     VAR
  1035.         {$IFC qDebug}
  1036.         id:                 INTEGER;
  1037.         kind:                ResType;
  1038.         segName:            Str255;
  1039.         s:                    MAName;
  1040.         seg:                Handle;
  1041.         {$ENDC}
  1042.         A5RegisterOnEntry:    LONGINT;
  1043.  
  1044.     BEGIN
  1045.     A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1046.  
  1047.     LoadMacAppSegment := pSegLoadPatch.oldTrapAddr;     { Where to go next }
  1048.  
  1049.     IF GetA5 <> A5RegisterOnEntry THEN
  1050.         BEGIN
  1051.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1052.         pLoadSegCalledFromOwnApp := FALSE;
  1053.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1054.         END
  1055.     ELSE
  1056.         BEGIN
  1057.         pLoadSegCalledFromOwnApp := TRUE;
  1058.         pOldResFile := MAUseResFile(gCodeRefNum);        { Must set a global because we return from
  1059.                                                          this function and then forward to the
  1060.                                                          actual segment loader which should also be
  1061.                                                          pointing to the _now_ correct resfile.
  1062.                                                          When we get called back again in
  1063.                                                          PostLoadMacAppSegment we will restore the
  1064.                                                          old resFile as the current resFile. Sorry
  1065.                                                          about the global. }
  1066.  
  1067.         {$IFC qDebug}
  1068.         IF NOT GetResLoad THEN
  1069.             BEGIN
  1070.             SetResLoad(TRUE);
  1071.             ProgramBreak('Whoops… LoadSeg called with resload set false');
  1072.             Failure(minErr, 0);                         {??? Assign an error code someday or
  1073.                                                          setresload to TRUE ???}
  1074.             END;
  1075.  
  1076.         {$ENDC}
  1077.  
  1078.         IF NOT PreloadSegmentResource(segNum) THEN
  1079.             BEGIN
  1080.             {$IFC qDebug}
  1081.             GetCallersMethodName(s);
  1082.             SetResLoad(FALSE);
  1083.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1084.                 seg := MAGet1Resource(kCode, segNum)
  1085.             ELSE
  1086.                 seg := MAGetResource(kCode, segNum);
  1087.             GetResInfo(seg, id, kind, segName);
  1088.             SetResLoad(TRUE);
  1089.             ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum), ' ',
  1090.                                 segName));
  1091.             {$ENDC}
  1092.             Failure(memFullErr, 0)
  1093.             END;
  1094.  
  1095.         gIsLoadedSeg^^[segNum] := TRUE;
  1096.  
  1097.         {$IFC qDebug}
  1098.         IF gSegReport THEN
  1099.             BEGIN
  1100.             { Cause the debugger to break at the start of the next routine. }
  1101.             gReportNext := TRUE;
  1102.             GetResInfo(gCodeSegs^^[segNum], id, kind, segName);
  1103.             gReportInfo := Concat(ConcatNumber('  *** Segment Loaded: ', segNum), ' ', segName);
  1104.             gSingleStep := gMemMgtBreak;
  1105.             END;
  1106.         {$ENDC}
  1107.  
  1108.         END;
  1109.     END;
  1110. {$Pop}
  1111.  
  1112. {--------------------------------------------------------------------------------------------------}
  1113. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1114.                                                          cannot call to any other segment from this
  1115.                                                          procedure }
  1116. {$Z+}
  1117. {$S MAMemoryRes}                                        { must be in Main segment }
  1118.  
  1119. PROCEDURE PostLoadMacAppSegment;
  1120.  
  1121.     VAR
  1122.         A5RegisterOnEntry:    LONGINT;
  1123.  
  1124.     BEGIN
  1125.     A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1126.  
  1127.     IF (GetA5 <> A5RegisterOnEntry) | NOT pLoadSegCalledFromOwnApp THEN
  1128.         BEGIN
  1129.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1130.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1131.         END
  1132.     ELSE
  1133.     { Called back from our glue.  Restores current res file pointer. }
  1134.         BEGIN
  1135.         IF pLoadSegCalledFromOwnApp THEN
  1136.             IF MAUseResFile(pOldResFile) <> 0 THEN;
  1137.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1138.  
  1139.         END;
  1140.     END;
  1141. {$Pop}
  1142.  
  1143. {--------------------------------------------------------------------------------------------------}
  1144. {$S MAMemoryRes}                                        { Must be in Main segment }
  1145.  
  1146. PROCEDURE LoadResidentSegments;
  1147.  
  1148.     VAR
  1149.         resIndex:            INTEGER;
  1150.         i:                    INTEGER;
  1151.         offset:             INTEGER;
  1152.         nameList:            Handle;
  1153.         segNumber:            INTEGER;
  1154.         p:                    SignedBytePtr;
  1155.         name:                Str255;
  1156.         seg:                Handle;
  1157.         theType:            ResType;
  1158.  
  1159.     BEGIN
  1160.     FOR resIndex := 1 TO CountResources('res!') DO
  1161.         BEGIN
  1162.         nameList := GetIndResource('res!', resIndex);
  1163.         HNoPurge(nameList);
  1164.  
  1165.         offset := 2;
  1166.         FOR i := 1 TO IntegerPtr(nameList^)^ DO
  1167.             BEGIN
  1168.             p := SignedBytePtr(ORD4(nameList^) + offset);
  1169.             BlockMove(Ptr(p), @name, p^ + 1);
  1170.             offset := offset + LENGTH(name) + 1;
  1171.  
  1172.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1173.                 seg := MAGet1NamedResource(kCode, name)
  1174.             ELSE
  1175.                 seg := MAGetNamedResource(kCode, name);
  1176.             IF seg <> NIL THEN
  1177.                 BEGIN
  1178.                 GetResInfo(seg, segNumber, theType, name);
  1179.                 SetResidentSegment(segNumber, TRUE);
  1180.                 END;
  1181.             END;
  1182.  
  1183.         HPurge(nameList);
  1184.         ReleaseResource(nameList);
  1185.         END;
  1186.     END;
  1187.  
  1188. {--------------------------------------------------------------------------------------------------}
  1189. {$S MAMemoryRes}
  1190.  
  1191. FUNCTION MemSpaceIsLow: BOOLEAN;
  1192.  
  1193.     BEGIN
  1194.     BuildAllReserves;
  1195.  
  1196.     MemSpaceIsLow := IsHandlePurged(pMemReserve);
  1197.     END;
  1198.  
  1199. {--------------------------------------------------------------------------------------------------}
  1200. {$S MAMemoryRes}
  1201.  
  1202. FUNCTION NewPermHandle(logicalSize: Size): Handle;
  1203.  
  1204.     CONST
  1205.         initVal             = $F3;                        { odd at all byte boundaries }
  1206.  
  1207.     VAR
  1208.         priorPerm:            BOOLEAN;
  1209.         {$IFC qDebug}
  1210.         aHandle:            Handle;
  1211.         {$EndC}
  1212.  
  1213.     BEGIN
  1214.     priorPerm := PermAllocation(TRUE);
  1215.     {$IFC NOT qDebug}
  1216.     NewPermHandle := NewHandle(logicalSize);
  1217.     {$ELSEC}
  1218.     aHandle := NewHandle(logicalSize);
  1219.     NewPermHandle := aHandle;
  1220.     {$Push} {$R-}
  1221.     IF aHandle <> NIL THEN
  1222.         BlockSet(aHandle^, logicalSize, initVal);
  1223.     {$Pop}
  1224.     {$EndC}
  1225.     pPermAllocation := priorPerm;
  1226.     END;
  1227.  
  1228. {--------------------------------------------------------------------------------------------------}
  1229. {$S MAMemoryRes}
  1230.  
  1231. FUNCTION NewPermPtr(logicalSize: Size): Ptr;
  1232.  
  1233.     CONST
  1234.         initVal             = $F5;                        { odd at all byte boundaries }
  1235.  
  1236.     VAR
  1237.         priorPerm:            BOOLEAN;
  1238.         {$IFC qDebug}
  1239.         aPtr:                Ptr;
  1240.         {$EndC}
  1241.  
  1242.     BEGIN
  1243.     priorPerm := PermAllocation(TRUE);
  1244.     {$IFC NOT qDebug}
  1245.     NewPermPtr := NewPtr(logicalSize);
  1246.     {$ELSEC}
  1247.     aPtr := NewPtr(logicalSize);
  1248.     NewPermPtr := aPtr;
  1249.     {$Push} {$R-}
  1250.     IF aPtr <> NIL THEN
  1251.         BlockSet(aPtr, logicalSize, initVal);
  1252.     {$Pop}
  1253.     {$EndC}
  1254.     pPermAllocation := priorPerm;
  1255.     END;
  1256.  
  1257. {--------------------------------------------------------------------------------------------------}
  1258. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1259. {$S MAMemoryRes}
  1260.  
  1261. FUNCTION PermAllocation(permanent: BOOLEAN): BOOLEAN;
  1262.  
  1263.     VAR
  1264.         b:                    BOOLEAN;
  1265.  
  1266.     BEGIN
  1267.     PermAllocation := pPermAllocation;
  1268.  
  1269.     IF permanent <> pPermAllocation THEN
  1270.         BEGIN
  1271.         pPermAllocation := permanent;
  1272.  
  1273.         IF permanent THEN
  1274.             BuildCodeReserve(kGZMaxAlloc, FALSE);
  1275.         END;
  1276.     END;
  1277. {$Pop}
  1278.  
  1279. {--------------------------------------------------------------------------------------------------}
  1280. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1281.                                                          cannot call to any other segment from this
  1282.                                                          procedure }
  1283. {$S MAMemoryRes}                                        { must be in Main segment }
  1284.  
  1285. FUNCTION PreloadSegmentResource(segNum: INTEGER): BOOLEAN;
  1286.  
  1287.     VAR
  1288.         seg:                Handle;
  1289.         err:                OSErr;
  1290.  
  1291.     PROCEDURE DoGetSegHandle;
  1292.  
  1293.         BEGIN
  1294.         seg := Get1Resource(kCode, segNum);
  1295.         END;
  1296.  
  1297.     BEGIN
  1298.     IF qDebug & pPermAllocation THEN
  1299.         BEGIN
  1300.         Writeln('segment # = ', segNum: 1);
  1301.         ProgramBreak('Trying to load a segment with PermAllocation = TRUE.');
  1302.         END;
  1303.  
  1304.     WithCodeResFileDo(DoGetSegHandle);
  1305.  
  1306.     IF seg = NIL THEN
  1307.         PreloadSegmentResource := FALSE
  1308.     ELSE
  1309.         BEGIN
  1310.         PreloadSegmentResource := TRUE;
  1311.  
  1312.         IF NOT IsHandleLocked(seg) THEN                 { not yet locked }
  1313.             LockHandleHigh(seg);
  1314.         END;
  1315.     END;
  1316.  
  1317. {--------------------------------------------------------------------------------------------------}
  1318. {$S MAMemoryRes}
  1319.  
  1320. PROCEDURE RemHandle(h: Handle;
  1321.                     toList: HandleListHandle);
  1322.  
  1323.     VAR
  1324.         p:                    LONGINT;
  1325.         maxP:                LONGINT;
  1326.         offset:             LONGINT;
  1327.  
  1328.     BEGIN
  1329.     p := Ord(toList^);                                    { Address of first element }
  1330.     maxP := p + GetHandleSize(Handle(toList));            { Address past last element }
  1331.  
  1332.     { Skip elements until item is found }
  1333.     WHILE (p < maxP) & (LongintPtr(p)^ <> Ord(h)) DO
  1334.         p := p + SizeOf(Handle);
  1335.  
  1336.     IF p < maxP THEN                                    { Item was found }
  1337.         BEGIN
  1338.         offset := Munger(Handle(toList), p - Ord(toList^), NIL, SizeOf(Handle), @h, 0);
  1339.         FailMemError;
  1340.         END;
  1341.     END;
  1342.  
  1343. {--------------------------------------------------------------------------------------------------}
  1344. {$S MAMemoryRes}
  1345. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1346.  
  1347. PROCEDURE ScanHandles(PROCEDURE DoToHandle(h: Handle));
  1348.  
  1349.     PROCEDURE ScanList(list: HandleListHandle);
  1350.  
  1351.         TYPE
  1352.             HandlePtr            = ^Handle;
  1353.  
  1354.         VAR
  1355.             i:                    INTEGER;
  1356.             p:                    HandlePtr;
  1357.  
  1358.         BEGIN
  1359.         i := GetHandleSize(Handle(list)) DIV SizeOf(Handle);
  1360.  
  1361.         p := HandlePtr(list^);
  1362.         WHILE i > 0 DO
  1363.             BEGIN
  1364.             DoToHandle(p^);
  1365.             p := HandlePtr(Ord(p) + SizeOf(Handle));
  1366.             i := i - 1;
  1367.             END;
  1368.         END;
  1369.  
  1370.     BEGIN
  1371.     ScanList(gCodeSegs);
  1372.     IF gApp1MemList <> NIL THEN
  1373.         ScanList(gApp1MemList);
  1374.     ScanList(gSysMemList);
  1375.     IF gApp2MemList <> NIL THEN
  1376.         ScanList(gApp2MemList);
  1377.     END;
  1378. {$Pop}
  1379.  
  1380. {--------------------------------------------------------------------------------------------------}
  1381. {$S MAMemoryRes}
  1382.  
  1383. PROCEDURE SetPermHandleSize(h: Handle;
  1384.                             newSize: Size);
  1385.  
  1386.     CONST
  1387.         initVal             = $F3;                        { odd at all byte boundaries }
  1388.  
  1389.     VAR
  1390.         priorPerm:            BOOLEAN;
  1391.         {$IFC qDebug}
  1392.         oldSize:            Size;
  1393.         {$EndC}
  1394.  
  1395.     BEGIN
  1396.     priorPerm := PermAllocation(TRUE);
  1397.     {$IFC qDebug}
  1398.     oldSize := GetHandleSize(h);
  1399.     {$EndC}
  1400.     SetHandleSize(h, newSize);
  1401.     pPermAllocation := priorPerm;                        { Since we are in the memory unit we can
  1402.                                                          break the encapsulation of the
  1403.                                                          PermAllocation Call to just set the
  1404.                                                          pPermAllocation flag back directly. This
  1405.                                                          lets us be assured that no operations have
  1406.                                                          occurred that would invalidate the MemErr
  1407.                                                          flag… thus the following call will give a
  1408.                                                          true result}
  1409.     FailMemError;
  1410.     {$IFC qDebug}
  1411.     {$Push} {$R-}
  1412.     IF oldSize < newSize THEN
  1413.         BlockSet(Ptr(Ord(h^) + oldSize), newSize - oldSize, initVal);
  1414.     {$Pop}
  1415.     {$EndC}
  1416.     END;
  1417.  
  1418. {--------------------------------------------------------------------------------------------------}
  1419. {$S MAMemoryRes}
  1420.  
  1421. PROCEDURE SetPermPtrSize(p: Ptr;
  1422.                          newSize: Size);
  1423.  
  1424.     CONST
  1425.         initVal             = $F5;                        { odd at all byte boundaries }
  1426.  
  1427.     VAR
  1428.         priorPerm:            BOOLEAN;
  1429.         {$IFC qDebug}
  1430.         oldSize:            Size;
  1431.         {$EndC}
  1432.  
  1433.     BEGIN
  1434.     priorPerm := PermAllocation(TRUE);
  1435.     {$IFC qDebug}
  1436.     oldSize := GetPtrSize(p);
  1437.     {$EndC}
  1438.     SetPtrSize(p, newSize);
  1439.     pPermAllocation := priorPerm;                        { Since we are in the memory unit we can
  1440.                                                          break the encapsulation of the
  1441.                                                          PermAllocation Call to just set the
  1442.                                                          pPermAllocation flag back directly. This
  1443.                                                          lets us be assured that no operations have
  1444.                                                          occurred that would invalidate the MemErr
  1445.                                                          flag… thus the following call will give a
  1446.                                                          true result}
  1447.     FailMemError;
  1448.     {$IFC qDebug}
  1449.     {$Push} {$R-}
  1450.     IF oldSize < newSize THEN
  1451.         BlockSet(Ptr(Ord(p) + oldSize), newSize - oldSize, initVal);
  1452.     {$Pop}
  1453.     {$EndC}
  1454.     END;
  1455.  
  1456. {--------------------------------------------------------------------------------------------------}
  1457. {$S MAMemoryRes}
  1458.  
  1459. PROCEDURE SetReserveSize(forCode, forOther: Size);
  1460.  
  1461.     VAR
  1462.         oldPerm:            BOOLEAN;
  1463.  
  1464.     BEGIN
  1465.     pSzCodeReserve := forCode;
  1466.     pSzMemReserve := forOther;
  1467.  
  1468.     { Since the numbers have changed, make sure we start from scratch. }
  1469.     pReserveExists := FALSE;
  1470.     EmptyHandle(pMemReserve);
  1471.  
  1472.     BuildAllReserves;
  1473.     END;
  1474.  
  1475. {--------------------------------------------------------------------------------------------------}
  1476. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1477.                                                          cannot call to any other segment from this
  1478.                                                          procedure }
  1479. {$S MAMemoryRes}                                        { must be in Main segment }
  1480.  
  1481. PROCEDURE SetResidentSegment(segNum: INTEGER;
  1482.                              makeResident: BOOLEAN);
  1483.  
  1484.     VAR
  1485.         {$IFC qDebug}
  1486.         id:                 INTEGER;
  1487.         kind:                ResType;
  1488.         segName:            Str255;
  1489.         s:                    MAName;
  1490.         {$ENDC}
  1491.         seg:                Handle;
  1492.  
  1493.     BEGIN
  1494.     IF makeResident THEN
  1495.         BEGIN
  1496.         gIsResidentSeg^^[segNum] := TRUE;
  1497.         IF NOT PreloadSegment(segNum) THEN
  1498.             BEGIN
  1499.             {$IFC qDebug}
  1500.             GetCallersMethodName(s);
  1501.             SetResLoad(FALSE);
  1502.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1503.                 seg := MAGet1Resource(kCode, segNum)
  1504.             ELSE
  1505.                 seg := MAGetResource(kCode, segNum);
  1506.             SetResLoad(TRUE);
  1507.             GetResInfo(seg, id, kind, segName);
  1508.             ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum),
  1509.                                 ' ', segName));
  1510.             {$ENDC}
  1511.             Failure(memFullErr, 0)
  1512.             END
  1513.         END
  1514.     ELSE
  1515.         BEGIN
  1516.         gIsResidentSeg^^[segNum] := FALSE;
  1517.         END;
  1518.     END;
  1519. {$Pop}
  1520.  
  1521. {--------------------------------------------------------------------------------------------------}
  1522. {$S MAMiniInit}
  1523.  
  1524. PROCEDURE SetStackSpace(numBytes: LONGINT);
  1525.  
  1526.     VAR
  1527.         curLimit:            LONGINT;
  1528.         newLimit:            LONGINT;
  1529.  
  1530.     BEGIN
  1531.     newLimit := Ord(GetCurStackBase) - numBytes;
  1532.  
  1533.     IF Ord(GetApplLimit) > newLimit THEN
  1534.         SetApplLimit(Ptr(newLimit));
  1535.     END;
  1536.  
  1537. {--------------------------------------------------------------------------------------------------}
  1538. {$S MAMemoryRes}
  1539. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1540.  
  1541. FUNCTION TotalTempSize(justLocked: BOOLEAN;
  1542.                        VAR canPurge: Handle): Size;
  1543.  
  1544.     VAR
  1545.         total:                Size;
  1546.         applZone:            THz;
  1547.  
  1548.     PROCEDURE TotalUp(h: Handle);
  1549.  
  1550.         VAR
  1551.             hIsLocked:            BOOLEAN;
  1552.  
  1553.         BEGIN
  1554.         IF NOT IsHandlePurged(h) THEN                    { in memory already }
  1555.             IF HandleZone(h) = applZone THEN            { in application heap }
  1556.                 BEGIN
  1557.                 HNoPurge(h);
  1558.  
  1559.                 hIsLocked := IsHandleLocked(h);
  1560.  
  1561.                 IF NOT justLocked | hIsLocked THEN
  1562.                     total := total + GetHandleSize(h) + 8;
  1563.                 { add in the size plus heap overhead }
  1564.  
  1565.                 IF NOT hIsLocked THEN
  1566.                     IF canPurge = NIL THEN
  1567.                         IF HandleIsEligible(h) THEN
  1568.                             canPurge := h;
  1569.                 END;
  1570.         END;
  1571.  
  1572.     BEGIN
  1573.     canPurge := NIL;
  1574.     total := 0;
  1575.     applZone := ApplicZone;
  1576.  
  1577.     ScanHandles(TotalUp);
  1578.  
  1579.     TotalTempSize := total;
  1580.     END;
  1581. {$Pop}
  1582.  
  1583. {--------------------------------------------------------------------------------------------------}
  1584. {$S MAMemoryRes}
  1585. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1586.  
  1587. PROCEDURE WithCodeResFileDo(PROCEDURE DoWithResFile);
  1588.  
  1589.     VAR
  1590.         oldResFile:         INTEGER;
  1591.  
  1592.     BEGIN
  1593.     oldResFile := MAUseResFile(gCodeRefNum);
  1594.     DoWithResFile;
  1595.     IF MAUseResFile(oldResFile) <> 0 THEN;
  1596.     END;
  1597. {$Pop}
  1598.  
  1599. {--------------------------------------------------------------------------------------------------}
  1600. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1601.                                                          cannot call to any other segment from this
  1602.                                                          procedure }
  1603. {$S MAMemoryRes}                                        { must be in Main segment }
  1604.  
  1605. PROCEDURE UnloadAllSegments;
  1606.  
  1607.     VAR
  1608.         i:                    LONGINT;
  1609.         seg:                Handle;
  1610.         jumpTablePtr:        LONGINT;
  1611.         oldResLoad:         BOOLEAN;
  1612.  
  1613.     PROCEDURE DoToFrame(calleeFrame: LONGINT;
  1614.                         ppc: LONGINT;
  1615.                         callerFrame: LONGINT;
  1616.                         itsFrame: LONGINT);
  1617.  
  1618.         VAR
  1619.             seg:                INTEGER;
  1620.  
  1621.         BEGIN
  1622.         seg := GetSegFromPC(ppc);
  1623.         IF (seg <> 0) & NOT gIsResidentSeg^^[seg] & gIsLoadedSeg^^[seg] THEN
  1624.             BEGIN
  1625.             Writeln('Segment#: ', seg: 2);
  1626.             ProgramBreak(
  1627.        'I really don''t think that you want to unload a segment into which you are going to return!'
  1628.                          )
  1629.             END;
  1630.         END;
  1631.  
  1632.     PROCEDURE UnloadEm;
  1633.  
  1634.         VAR
  1635.             i:                    integer;
  1636.  
  1637.         BEGIN
  1638.         FOR i := 1 TO pMaxSegNum DO
  1639.             IF NOT gIsResidentSeg^^[i] & gIsLoadedSeg^^[i] THEN
  1640.                 BEGIN
  1641.                 seg := gCodeSegs^^[i];
  1642.                 IF (seg <> NIL) & NOT IsHandlePurged(seg) THEN
  1643.                     BEGIN
  1644.                     UnLoadSeg(Ptr(jumpTablePtr + IntegerHandle(seg)^^ + 2));
  1645.                     gIsLoadedSeg^^[i] := FALSE;
  1646.                     END;
  1647.                 END;
  1648.         END;
  1649.  
  1650.     BEGIN
  1651.     {$IFC qDebug}
  1652.     CheckRsrcUsage;
  1653.     {$ENDC}
  1654.  
  1655.     IF gUnloadAllSegs THEN
  1656.         BEGIN
  1657.         jumpTablePtr := Ord(GetA5) + GetCurJTOffset;
  1658.  
  1659.         {$IFC qDebug}
  1660.         EachFrameDo(Ord(GetCurStackFramePtr), Ord(GetCurStackFramePtr) + 4, DoToFrame);
  1661.         {$EndC}
  1662.  
  1663.         WithCodeResFileDo(UnloadEm);
  1664.  
  1665.         {$IFC qDebug}
  1666.         IF gSegReport THEN
  1667.             ProgramReport('  *** Just unloaded all segments ***', gMemMgtBreak);
  1668.         {$ENDC}
  1669.         END;
  1670.     END;
  1671. {$Pop}
  1672.  
  1673. {--------------------------------------------------------------------------------------------------}
  1674. {$IFC qDebug}
  1675. {$S MADebug}
  1676.  
  1677. PROCEDURE WriteReserves;
  1678.  
  1679. { WRITELN's the temporary reserve and low-memory reserves in the
  1680. debug window. }
  1681.  
  1682.     BEGIN
  1683.     WrLblPtr('Temporary reserve (pCodeReserve)', pCodeReserve); Writeln;
  1684.     WrLblPtr('Low-memory reserve (pMemReserve)', pMemReserve); Writeln;
  1685.     END;
  1686. {$ENDC}
  1687.